package com.un.ebs.sale.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.contract.domain.ContractItemExt;
import com.un.ebs.contract.domain.ContractItemWriteOffDetailExt;
import com.un.ebs.contract.dto.ContractVo;
import com.un.ebs.contract.service.ContractService;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.inventory.domain.InventoryNoteItemExt;
import com.un.ebs.inventory.service.InventoryNoteService;
import com.un.ebs.sale.domain.*;
import com.un.ebs.sale.dto.SaleDeliverNoteItemDto;
import com.un.ebs.sale.dto.SaleDeliverNoteUpdateDto;
import com.un.ebs.sale.dto.SaleDeliverNoteVo;
import com.un.ebs.sale.mapper.*;
import com.un.ebs.sale.service.SaleDeliverNoteService;
import com.un.ebs.sale.service.SaleOrderService;
import com.un.ebs.sys.domain.EntLinkman;
import com.un.ebs.sys.service.EntService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * (TbSaleDeliverNote)表服务实现类
 *
 * @author liubo
 * @since 2020-08-19 12:17:10
 */
@Service
public class SaleDeliverNoteServiceImpl extends ServiceImpl<SaleDeliverNoteMapper, SaleDeliverNote> implements SaleDeliverNoteService {

    @Resource
    private ContractService contractService;

    @Resource
    private InventoryNoteService inventoryNoteService;

    @Resource
    private SaleOrderService saleOrderService;

    @Resource
    private SaleDeliverNoteItemMapper saleDeliverNoteItemMapper;

    @Resource
    private SaleDeliverNoteExtMapper saleDeliverNoteExtMapper;

    @Resource
    private SaleDeliverNoteItemExtMapper saleDeliverNoteItemExtMapper;

    @Resource
    private SaleDeliverItemViewMapper saleDeliverItemViewMapper;

    @Resource
    private EntService entService;

    @Transactional
    @Override
    public String save(SaleDeliverNoteUpdateDto req) {
        SaleDeliverNote obj;
        if (StringUtils.isNullOrEmpty(req.getId())) {
            obj = new SaleDeliverNote();
            obj.setCode(String.format("SD-%s%04d", DateUtils.formatDate(new Date(), "yyyyMM"), baseMapper.maxCode() + 1));
        } else {
            obj = getById(req.getId());
            if (obj.getSubmitStatus()) {
                throw new BusinessException("单据已提交，不能修改。");
            }
        }

        if (StringUtils.isNullOrEmpty(req.getDeliverTypeDict())) {
            throw new BusinessException("请指定发运方式。");
        }

        ContractVo contract = contractService.queryViewByCode(req.getContractCode());
        if (contract == null) {
            throw new BusinessEntityNotFoundException(req.getContractCode(), "销售合同");
        }

        entService.updateLinkman(contract.getBusinessEntId(), req.getPhone(), req.getLinkman(), req.getDeliverAdd());

        obj.setSaleContractCode(contract.getCode());
        obj.setCustomerEntId(contract.getBusinessEntId());
        obj.setCustomerEntName(contract.getBusinessEntName());
        obj.setDeliverAdd(req.getDeliverAdd());
        obj.setDeliverDate(req.getDeliverDate());
        obj.setDeliverTypeDict(req.getDeliverTypeDict());
        obj.setLinkman(req.getLinkman());
        obj.setPhone(req.getPhone());
        obj.setRemark(req.getRemark());
        obj.setPurchaseOrderCode(req.getPurchaseOrderCode());
        obj.setSubmitStatus(false);
        obj.insertOrUpdate();

        LambdaQueryWrapper<SaleDeliverNoteItem> lq = Wrappers.lambdaQuery();
        lq.eq(SaleDeliverNoteItem::getNoteId, req.getId());
        saleDeliverNoteItemMapper.delete(lq);

        for (SaleDeliverNoteItemDto item : req.getItems()) {
            Optional<ContractItemExt> contractItem = contract.getItems().stream().filter(s -> s.getSkuId().equals(item.getSkuId())).findFirst();
            if (!contractItem.isPresent()) {
                throw new BusinessException(String.format("%s 合同中没有此产品。", req.getContractCode()));
            }

            try {
                LambdaQueryWrapper<SaleDeliverNoteItemExt> query = Wrappers.lambdaQuery();
                query.eq(SaleDeliverNoteItemExt::getInventoryNoteItemId, item.getInventoryNoteItemId());
                SaleDeliverNoteItemExt hasItem = saleDeliverNoteItemExtMapper.selectOne(query);
                if (hasItem != null) {
                    if (hasItem.getSubmitStatus()) {
                        throw new BusinessException(String.format(" %s 出库单已装箱，不能重复装箱。", hasItem.getNoteCode()));
                    } else {
                        throw new BusinessException(String.format(" %s 出库单已装箱，但未提交，请提交或删除装箱单。", hasItem.getNoteCode()));
                    }
                }
            } catch (MyBatisSystemException e) {
                throw new BusinessException("装箱单重复。");
            }

            InventoryNoteItemExt itemExt = inventoryNoteService.queryItemByItemId(item.getInventoryNoteItemId());
            if (itemExt == null) {
                throw new BusinessException("出库明细没有找到。");
            }
            SaleDeliverNoteItem objItem = new SaleDeliverNoteItem();
            objItem.setInventoryNoteId(itemExt.getNoteId());
            objItem.setInventoryNoteItemId(item.getInventoryNoteItemId());
            objItem.setNoteId(obj.getId());
            objItem.setQty(itemExt.getQty());
            objItem.setPrice(contractItem.get().getPrice());
            objItem.setSkuId(item.getSkuId());
            objItem.setRemark(item.getRemark());
            objItem.insert();
        }
        return obj.getId();
    }

    @Override
    public String addByContract(String saleContractCode) {

        ContractVo contract = contractService.queryViewByCode(saleContractCode);
        if (contract == null) {
            throw new BusinessEntityNotFoundException(saleContractCode, "销售合同");
        }
        if (!contract.getAuditStatus()) {
            throw new BusinessException("销售合同没有审批。");
        }

        SaleDeliverNoteUpdateDto obj = new SaleDeliverNoteUpdateDto();
        obj.setContractCode(saleContractCode);

        EntLinkman linkman = entService.queryLinkmanByDefault(contract.getBusinessEntId());
        if (linkman != null) {
            obj.setLinkman(linkman.getName());
            obj.setPhone(linkman.getPhone());
            obj.setDeliverAdd(linkman.getAddress());
            obj.setDeliverTypeDict(linkman.getDefaultDeliverTypeDict());
        }

        obj.setDeliverDate(new Date());

        // 查询可交付的出库单
        List<SaleDeliverNoteItemDto> items = new ArrayList<>();
        List<SaleOrderExt> list = saleOrderService.queryByContractCode(saleContractCode);
        if (StringUtils.isNullOrEmpty(list)) {
            throw new BusinessException("销售合同没有订单记录。");
        }
        for (SaleOrderExt order : list) {
            List<InventoryNoteItemExt> noteItems = inventoryNoteService.queryItemExtByRelationNoteId(order.getId());
            for (InventoryNoteItemExt item : noteItems) {
                if (!item.getSubmitStatus() || !item.getAuditStatus()) {
                    throw new BusinessException(String.format("出库单【%s】未审核，请通知库房审核后，再执行此操作。", item.getCode()));
                }

                SaleDeliverNoteItemDto objItem = new SaleDeliverNoteItemDto();
                objItem.setSkuId(item.getSkuId());
                objItem.setQty(item.getQty());
                objItem.setInventoryNoteItemId(item.getId());
                items.add(objItem);
            }
        }
        if (!StringUtils.isNullOrEmpty(items)) {
            obj.setItems(items);
            return save(obj);
        }
        throw new BusinessException("没有可供装箱的出库单。");
    }

    @Override
    public SaleDeliverNoteVo queryCanDeliverNote(String saleContractCode) {
        ContractVo contract = contractService.queryViewByCode(saleContractCode);
        if (contract == null) {
            throw new BusinessEntityNotFoundException(saleContractCode, "合同");
        }

        SaleDeliverNoteVo obj = new SaleDeliverNoteVo();
        obj.setSaleContractCode(saleContractCode);
        obj.setCustomerEntId(contract.getBusinessEntId());
        obj.setCustomerEntName(contract.getBusinessEntName());
        obj.setDeliverDate(new Date());

        List<SaleDeliverNoteItemExt> items = new ArrayList<>();
        List<InventoryNoteItemExt> noteItems = inventoryNoteService.queryItemExtByContractCode(saleContractCode);

        for (InventoryNoteItemExt item : noteItems) {
            if (!item.getSubmitStatus() || !item.getAuditStatus()) {
                continue;
            }
            Optional<ContractItemExt> contractItem = contract.getItems().stream().filter(s -> s.getSkuId().equals(item.getSkuId())).findFirst();
            if (!contractItem.isPresent()) {
                continue;
            }
            Double deliverQty = 0d;
            System.out.println(item.getNoteId());
            Boolean status = baseMapper.queryDeliverStatusBySku(item.getNoteId(), item.getSkuId());
            if (status != null) {
                if (status) {
                    deliverQty = baseMapper.queryDeliverQty(item.getNoteId(), item.getSkuId());
                    if (item.getQty() <= deliverQty) {
                        continue;
                    }
                } else {
                    SaleDeliverNoteItemExt itemExt = baseMapper.selectItemByInventoryNoteIdAndSkuId(item.getNoteId(),item.getSkuId());
                    if(itemExt!=null){
                        throw new BusinessException(String.format("销售装箱单【%s】未审核，请直接审核该装箱单。", itemExt.getCode()));
                    }else{
                        throw new BusinessException(String.format("销售出库单【%s】未审核。", item.getCode()));
                    }
                }
            }

            SaleDeliverNoteItemExt objItem = new SaleDeliverNoteItemExt();
            objItem.setDeliverQty(new BigDecimal(item.getQty()).subtract(new BigDecimal(deliverQty)).doubleValue());
            objItem.setSkuId(item.getSkuId());
            objItem.setSkuCode(item.getSkuCode());
            objItem.setSkuName(item.getNameAs());
            objItem.setNoteCode(item.getCode());
            objItem.setInventoryNoteItemId(item.getId());
            objItem.setInventoryNoteId(item.getNoteId());
            objItem.setDeliverPrice(contractItem.get().getPrice());
            items.add(objItem);
        }
        obj.setItems(items);

        //如果是正式合同，则看看有没有核销的
        if (!contract.getIsTemp()) {
            obj.getItems().addAll(baseMapper.queryCanDeliverInventoryNoteItem(contract.getCode()).stream().map(s -> {
                SaleDeliverNoteItemExt item = new SaleDeliverNoteItemExt();
                item.setSkuId(s.getSkuId());
                item.setSkuCode(s.getSkuCode());
                item.setSkuName(s.getSkuName());
                item.setDeliverQty(s.getNotDeliverQty());
                item.setDeliverPrice(s.getPrice());
                item.setInventoryNoteId(s.getInventoryNoteId());
                item.setInventoryNoteItemId(s.getInventoryNoteItemId());
                item.setNoteCode(s.getInventoryNoteCode());
                return item;
            }).collect(Collectors.toList()));
        }
        return obj;
    }

    @Override
    public void submit(String id) {
        SaleDeliverNote obj = getById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "装箱单");
        }

        if (obj.getSubmitStatus()) {
            throw new BusinessException("装箱单已经提交。");
        }

        if (!baseMapper.queryInventoryNoteAuditStatus(id)) {
            throw new BusinessException("销售出库单未审核。");
        }

        obj.setSubmitStatus(true);
        obj.setSubmitAt(SecurityUtils.getUserContent().getId());
        obj.setSubmitAtName(SecurityUtils.getUserContent().getPersonnelName());
        obj.setSubmitTime(new Date());
        obj.updateById();
    }

    @Override
    public void submitCancel(String id) {
        SaleDeliverNote obj = getById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "装箱单");
        }

        if (!obj.getSubmitStatus()) {
            throw new BusinessException("装箱单未提交。");
        }

        if(baseMapper.selectCountByIsBack(id)>0){
            throw new BusinessException("当前装箱单存在系统自动生成的销售退货单，不可以撤销。");
        }

        obj.setSubmitStatus(false);
        obj.setSubmitAt(null);
        obj.setSubmitAtName(null);
        obj.setSubmitTime(null);
        obj.updateById();
    }

    @Override
    public void delete(String id) {
        SaleDeliverNote obj = getById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "装箱单");
        }
        if (obj.getSubmitStatus()) {
            throw new BusinessException("装箱单已经提交。");
        }
        obj.deleteById();
    }

    @Override
    public SaleDeliverNoteExt queryById(String id) {
        return saleDeliverNoteExtMapper.selectById(id);
    }

    @Override
    public SaleDeliverNoteVo queryViewId(String id) {
        SaleDeliverNoteExt objExt = saleDeliverNoteExtMapper.selectById(id);
        if (objExt == null) {
            return null;
        }

        SaleDeliverNoteVo objVo = new SaleDeliverNoteVo();
        BeanUtils.copyProperties(objExt, objVo);
        objVo.setItems(queryItemById(id));
        return objVo;
    }

    @Override
    public IPage<SaleDeliverNoteExt> query(String searchText, int pageSize, int pageIndex) {
        Page<SaleDeliverNoteExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<SaleDeliverNoteExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.eq(SaleDeliverNoteExt::getCode, searchText).or()
                    .eq(SaleDeliverNoteExt::getSaleContractCode, searchText);
        }
        lq.eq(SaleDeliverNoteExt::getIsDelete, false);
        lq.orderByDesc(SaleDeliverNoteExt::getCreateTime);
        return saleDeliverNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public List<SaleDeliverNoteItemExt> queryItemById(String id) {
        LambdaQueryWrapper<SaleDeliverNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleDeliverNoteItemExt::getNoteId, id);
        return saleDeliverNoteItemExtMapper.selectList(lq);
    }

    @Override
    public IPage<SaleDeliverNoteItemExt> queryItem(String searchText, int pageSize, int pageIndex) {
        Page<SaleDeliverNoteItemExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleDeliverNoteItemExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.eq(SaleDeliverNoteItemExt::getNoteCode, searchText).or()
                    .eq(SaleDeliverNoteItemExt::getCode, searchText).or()
                    .eq(SaleDeliverNoteItemExt::getSkuCode, searchText).or()
                    .eq(SaleDeliverNoteItemExt::getSaleContractCode, searchText).or()
                    .like(SaleDeliverNoteItemExt::getSkuName, searchText);
        }
        lq.orderByDesc(SaleDeliverNoteItemExt::getCreateTime);
        return saleDeliverNoteItemExtMapper.selectPage(page, lq);
    }

    @Override
    public List<SaleDeliverItemView> queryItemByContract(String contractCode) {
        LambdaQueryWrapper<SaleDeliverItemView> lq = Wrappers.lambdaQuery();
        lq.eq(SaleDeliverItemView::getSaleContractCode, contractCode);
        return saleDeliverItemViewMapper.selectList(lq);
    }

    @Override
    public List<SaleDeliverNoteItemExt> queryNoteItemByContract(String contractCode) {
        LambdaQueryWrapper<SaleDeliverNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleDeliverNoteItemExt::getSaleContractCode, contractCode);
        lq.eq(SaleDeliverNoteItemExt::getSubmitStatus, true);
        return saleDeliverNoteItemExtMapper.selectList(lq);
    }

    @Override
    public SaleDeliverNoteExt queryNoteByInventoryNoteId(String inventoryNoteId) {
        LambdaQueryWrapper<SaleDeliverNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleDeliverNoteItemExt::getInventoryNoteId,inventoryNoteId);
        lq.eq(SaleDeliverNoteItemExt::getSubmitStatus,true);
        Optional<SaleDeliverNoteItemExt> item= saleDeliverNoteItemExtMapper.selectList(lq).stream().findFirst();
        if(!item.isPresent()){
            throw new BusinessException("指定的销售出库单没有找到。");
        }

        return baseMapper.selectViewById(item.get().getNoteId());
    }

    @Override
    public boolean queryDeliverStatus(String inventoryNoteId) {
        Boolean status = baseMapper.queryDeliverStatus(inventoryNoteId);
        if (status == null) {
            return false;
        } else {
            return status;
        }
    }
}
